/*   
 * Copyright 2009-2010 Rob Schoening
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 *    
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

package org.beaconframework.sampler;

import groovy.lang.Binding;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovyShell;
import groovy.lang.MissingPropertyException;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.commons.io.IOUtils;

import org.beaconframework.util.ThreadContext;
import org.beaconframework.util.exception.BeaconException;
import org.beaconframework.vaadin.util.VaadinContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ResourceLoader;

import com.vaadin.Application;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

public class GroovySampler extends Panel {
	

    public static Component load(String path) {

        try {
            Application app = VaadinContext.getApplication();

            ScriptInfo si = findScript(path);

            Binding se = new Binding();

            se.setVariable("application", app);
            se.setVariable("mainWindow", app.getMainWindow());
            se.setVariable("applicationContext", VaadinContext
                    .getApplicationContext());
            se.setVariable("executionContext", ThreadContext.get());

            GroovyShell gs = new GroovyShell(se);
            gs.evaluate("loadComponent = { "
                    + GroovySampler.class.getName() + ".load(it) }");

            Component c = (Component) gs.evaluate(si.script);
            log.debug("Loaded component: {}", c);
            return c;
        } catch (GroovyRuntimeException e) {
            throw new BeaconException(e);
        }
    }

    public static class ScriptInfo {
        String script;
        String extension;

        public String getScript() {
            return script;
        }

        public String getExtension() {
            return extension;
        }

    }

    public static ScriptInfo findScript(String name) {

        String extension = "groovy";
        try {

            String path = name;// + "." + extension;
            org.springframework.core.io.Resource r = VaadinContext
                    .getApplicationContext().getResource(
                            ResourceLoader.CLASSPATH_URL_PREFIX + path);

            if (r != null && r.exists()) {

                InputStream in = r.getInputStream();
                ScriptInfo si = new ScriptInfo();
                si.script = IOUtils.toString(in);
                si.extension = extension;
                return si;
            }

            r = VaadinContext.getApplicationContext().getResource(path);
            if (r != null && r.exists()) {
                InputStream in = r.getInputStream();
                ScriptInfo si = new ScriptInfo();
                si.script = IOUtils.toString(in);
                si.extension = extension;
                return si;
            }

            log.info("Could not find: {}", path);

        } catch (IOException e) {
            log.warn("", e);
        }

        return null;

    }
    /**
	 * 
	 */
    private static final long serialVersionUID = 1L;
    public static final String DEFAULT_SCRIPT = "import com.vaadin.ui.*\nimport org.beaconframework.wps.vaadin.user.*\n\n";
    public static Logger log = LoggerFactory.getLogger(GroovySampler.class);
    Label itextField = new Label();

    Button runScriptButton = new Button("Run Script");
    VerticalLayout samplerLayout;
    String script = "";
    VerticalLayout scriptLayout;
    TextField scriptTextField;
    TabSheet tabSheet;

    public GroovySampler() {

        super();

        setSizeFull();
        tabSheet = new TabSheet();
        addComponent(itextField);
        addComponent(tabSheet);
        script = DEFAULT_SCRIPT;
        samplerLayout = new VerticalLayout();

        itextField.setContentMode(Label.CONTENT_TEXT);

        tabSheet.addTab(samplerLayout, "Sample", null);

        scriptLayout = new VerticalLayout();
        scriptTextField = new TextField("Source", script);
        scriptTextField.setColumns(40);
        scriptTextField.setRows(10);
        scriptLayout.addComponent(scriptTextField);
        scriptLayout.addComponent(runScriptButton);

        tabSheet.addTab(scriptLayout, "Groovy Source", null);

        ClickListener cl = new Button.ClickListener() {

            /**
			 * 
			 */
            private static final long serialVersionUID = 1L;

            public void buttonClick(ClickEvent event) {
                script = scriptTextField.getValue().toString();
                update();

            }
        };
        runScriptButton.addListener(cl);
    }

    public String getScript() {
        return script;
    }




    String loadScript(String resource) {

    	
        ScriptInfo si = findScript(resource);
        if (si==null) {
        	return null;
        }
        String s = null;
       s = si.getScript();

        if (log.isDebugEnabled()) {
            log.debug("Sampler Script\n" + s);
        }

        return s;
    }
    String loadScript(Class<? extends Component> c) {

        ScriptInfo si = findScript("/"+(c.getName().replace('.', '/'))+"Sampler");
        String s = null;
        if (si==null) {
        
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            String unqualifiedClassName = c.getName().substring(
                    c.getPackage().getName().length() + 1);
            pw.println("import com.vaadin.ui.*");
            pw.println("import " + GroovySampler.class.getPackage().getName()
                    + ".*");
            pw.println("import " + c.getPackage().getName() + ".*");
            pw.println();
            pw.println("c = new " + unqualifiedClassName + "()");
            pw.println();
            pw.println("return c;");
            pw.flush();
            s = sw.toString();
            
        } else {
        	s = si.getScript();
        }

        if (log.isDebugEnabled()) {
            log.debug("Sampler Script\n" + s);
        }

        return s;
    }

    public void setScriptResource(String s) {
    	setScript(loadScript(s));
    	update();
    }

    public void setComponentClass(Class<? extends Component> c) {
        setScript(loadScript(c));
        //itextField.setValue(loadText(c));
        update();
    }

    public void setScript(String script) {
        this.script = script;
        scriptTextField.setValue(script);
    }

    public void update() {
        Binding binding = new Binding();
        samplerLayout.removeAllComponents();
        binding.setVariable("layout", samplerLayout);
        GroovyShell shell = new GroovyShell(binding);
        if (script==null) {
        	return;
        }
        try {
            Object rval = shell.evaluate(script);
            if (rval != null && rval instanceof Component) {
                Component child = (Component) rval;
                if (child.getParent() == null) {
                    samplerLayout.addComponent(child);
                }
            }
        } catch (MissingPropertyException p) {
            p.printStackTrace();
        }
        tabSheet.setSelectedTab(samplerLayout);

    }

}
